package com.jdone.compus.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jdone.compus.dto.RefundRequestDto;
import com.jdone.compus.dto.RefundResponseDto;
import com.jdone.compus.enums.OrderStatus;
import com.jdone.compus.model.BlowUsageRecord;
import com.jdone.compus.repository.BlowUsageRecordRepository;
import com.jdone.compus.utils.SignUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Service
@Slf4j
@RequiredArgsConstructor
public class RefundService {

    @Value("${payment.platform.url}")
    private String platformUrl;

    @Value("${payment.platform.apiKey}")
    private String apiKey;

    @Value("${payment.platform.myappId}")
    private String myappId;

    private final BlowUsageRecordRepository usageRepo;
    private final RestTemplate restTemplate;
    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 根据业务订单号发起退款，生成 TK+16 位随机退款单号
     */
    @Transactional
    public String refundByBusinessOrderNo(String businessOrderNo) {
        // 1. 查询记录
        BlowUsageRecord record = usageRepo.findByBusinessOrderNo(businessOrderNo)
                .orElseThrow(() -> new IllegalArgumentException("业务订单不存在: " + businessOrderNo));

        // 2. 生成退款单号并回写
        String outRefundNo = generateOutRefundNo();
        record.setOutRefundNo(outRefundNo);

        // 3. 构造请求 DTO
        RefundRequestDto req = buildRefundRequest(record, outRefundNo);

        // 4. 调签名
        attachSignature(req);

        // 5. 调用平台接口
        String s = callRefundApi(req);

        // 6. 一次性写库
        record.setOrderStatus(OrderStatus.CANCELLED);
        usageRepo.save(record);

        //根据平台返回的data对象
        return s;
    }

    private String generateOutRefundNo() {
        return "TK" + IntStream.range(0, 16)
                .mapToObj(i -> String.valueOf(ThreadLocalRandom.current().nextInt(10)))
                .collect(Collectors.joining());
    }

    private RefundRequestDto buildRefundRequest(BlowUsageRecord record, String outRefundNo) {
        RefundRequestDto req = new RefundRequestDto();
        req.setMyapp_id(myappId);
        req.setNonce_str(UUID.randomUUID().toString().replace("-", ""));
        req.setOut_trade_no(record.getBusinessOrderNo());
        req.setOut_refund_no(outRefundNo);

        // fee 单位：元 -> 分
        int refundFen = record.getFee()
                .multiply(BigDecimal.valueOf(100))
                .intValueExact();
        req.setRefund_amount(refundFen);
        req.setRefund_desc("用户申请退款");

        return req;
    }

    private void attachSignature(RefundRequestDto req) {
        // Bean -> Map<String, Object>
        Map<String, Object> rawMap = MAPPER.convertValue(req, new TypeReference<Map<String, Object>>() {
        });
        // 过滤 null/空，转 Map<String,String>
        Map<String, String> params = rawMap.entrySet().stream()
                .filter(e -> e.getValue() != null && !String.valueOf(e.getValue()).trim().isEmpty())
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        e -> String.valueOf(e.getValue()).trim()
                ));
        // 生成签名并设置
        String sign = SignUtil.generateSign(params, apiKey);
        req.setSign(sign);
    }


    public String callRefundApi(RefundRequestDto req) {
        String url = platformUrl + "/golivepay/refund/unifiedRefund";

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<RefundRequestDto> entity = new HttpEntity<>(req, headers);

        // 直接以 String 接收完整响应体
        ResponseEntity<String> response = restTemplate.exchange(
                url, HttpMethod.POST, entity, String.class);

        if (response.getStatusCode() != HttpStatus.OK || response.getBody() == null) {
            log.error("调用退款接口失败, status={}, body={}", response.getStatusCode(), response.getBody());
            throw new RuntimeException("调用退款接口失败, HTTP " + response.getStatusCodeValue());
        }

        try {
            // 用 Jackson 把最外层 JSON 解析，取出 data 节点
            ObjectMapper mapper = new ObjectMapper();
            JsonNode root = mapper.readTree(response.getBody());
            JsonNode dataNode = root.path("data");
            if (dataNode.isMissingNode()) {
                throw new RuntimeException("调用退款接口成功，但未找到 data 字段");
            }
            // 直接把 data 节点重新序列化成字符串返回
            return mapper.writeValueAsString(dataNode);
        } catch (JsonProcessingException e) {
            log.error("解析退款接口返回值失败", e);
            throw new RuntimeException("解析退款接口返回值失败", e);
        }
    }
}
